"""
Copyright © 2021 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython-espnow-practice-gui
"""
from machine import I2C, Pin
from struct import pack
import framebuf
from .fonts.fontdata import FontData
from drivers.ssd1306 import SSD1306_I2C


class ControllerGui(object):
	def __init__(self, oled=None):
		self.__oled = oled
		self.__oled_width = 128
		self.__oled_height = 64
		self.__font_width = FontData.FONT_WIDTH
		self.__font_height = FontData.FONT_HEIGHT
		self.__format = FontData.FORMAT
		self.__fontdata = FontData()
		self.__indent = int(self.__font_width // 2)
		self.__rows_per_page = int(self.__oled_height // self.__font_height)
		self.__cols_per_page = int(self.__oled_width // self.__font_width)

		if self.__oled:
			self.__oled_width = self.__oled.width
			self.__oled_height = self.__oled.height

		self.clean_screen(True)

	def reset_pos(self):
		'''
		重置当前坐标为原点
		'''
		self.__pos_x = int((self.__oled_width - self.__cols_per_page * self.__font_width) // 2)
		self.set_pos_y(self.__rows_per_page)

	def clean_screen(self, show=False):
		'''
		清空屏幕并重置坐标
		'''
		self.reset_pos()

		self.__oled.fill(0)
		if show: self.show()

	def newline(self, times=1):
		'''
		设置指定数量的换行，默认 1 行
		'''
		self.__pos_x = 0
		self.__pos_y += self.__font_height * times

	def set_pos_y(self, lines):
		'''
		根据指定行数设置 y 轴顶点，假设每屏可显示 5 行，要输出 3 行内容，那么 y 轴顶点计算公式为：(5 - 3) / 2
		'''
		self.__pos_y = int((self.__oled_height - self.__font_height * lines) // 2)

	def draw_text(self, chars, indent=False):
		'''
		输出指定字符串，可识别 换行 和 空格，如果输出内容为 ASCII 字符，可设置 indent=True 进行位置缩进
		'''
		for char in chars:
			if ord(char) == 10:
				self.newline()
				continue
			elif ord(char) == 32:
				self.__pos_x += self.__font_width
				continue

			self.__fill_buffer(self.__fontdata.get_buffer(char))
			self.__pos_x += self.__indent if indent else self.__font_width

	def show_group(self, index):
		'''
		输出分组信息
		'''
		chars = f'{index + 1}'

		self.reset_pos()
		self.draw_text(FontData.ICON_GROUP)
		self.draw_text(chars, True)

	def clean_line(self):
		'''
		清除当前行内容
		'''
		self.__oled.fill_rect(self.__pos_x, self.__pos_y, self.__oled_width, self.__font_height, 0)

	def show(self):
		self.__oled.show()

	def show_client_status(self, index, status):
		'''
		显示 客户端 状态信息
		'''
		clients = FontData.ICON_CLIENTS
		spaces = f"{' ' * index}"

		self.reset_pos()
		self.newline()
		self.draw_text(f'{spaces}{clients[index]}')
		self.newline()
		self.draw_text(f'{spaces}{status}')

	def clean_clients(self):
		'''
		清除全部 客户端 状态信息
		'''
		self.reset_pos()
		self.newline()
		self.clean_line()
		self.newline()
		self.clean_line()

	def show_splash_screen(self):
		'''
		显示 启动页 内容信息
		'''
		chars = ' Led\n  Control\n   Pad'

		self.__oled.fill_rect(0, 0, 5, self.__oled_height, 1)
		self.__oled.fill_rect(self.__oled_width - 5, 0, 5, self.__oled_height, 1)

		self.reset_pos()
		self.set_pos_y(3)
		self.draw_text(chars, True)
		self.show()
		# self.__export_bmp('splash')

	def __fill_buffer(self, buffer):
		if isinstance(buffer, (bytes, memoryview)):
			buffer = framebuf.FrameBuffer(bytearray(buffer), self.__font_width, self.__font_height, self.__format)
		self.__oled.blit(buffer, self.__pos_x, self.__pos_y)

	def export_bmp(self, filename):
		identify = b'BM'
		reserved = 0
		header_size = const(62)
		bmp_header = const(40) # windows bitmap
		bmp_width = self.__oled_width
		bmp_height = self.__oled_height
		bmp_planes = 1
		bmp_bit_count = 1
		bmp_compression = 0
		bmp_data_size = int(bmp_width * bmp_height // 8)
		bmp_x_ppm = 0
		bmp_y_ppm = 0
		bmp_color_used = 0
		bmp_color_important = 0
		bmp_color_table_w = 0x00000000
		bmp_color_table_b = 0x00ffffff
		filesize = header_size + bmp_data_size

		bmp_header_data = pack(
			'<2s6I2H6I2I',
			# BITMAPFILEHEADER
			identify,			# 2
			filesize,			# 4
			reserved,			# 4
			header_size,		# 4

			# BITMAPINFOHEADER
			bmp_header,			# 4
			bmp_width,			# 4
			bmp_height * -1,	# 4
			bmp_planes,			# 2
			bmp_bit_count,		# 2
			bmp_compression,	# 4
			bmp_data_size,		# 4
			bmp_x_ppm,			# 4
			bmp_y_ppm,			# 4
			bmp_color_used,		# 4
			bmp_color_important,# 4

			# RGBQUAD
			bmp_color_table_w,	# 4
			bmp_color_table_b,	# 4
		)

		bmp_content_data = bytearray(bmp_data_size)
		converter = framebuf.FrameBuffer(bmp_content_data, self.__oled_width, self.__oled_height, framebuf.MONO_HLSB)
		converter.blit(self.__oled, 0, 0)

		with open(f'{filename}.bmp', 'wb') as bmp:
			bmp.write(bmp_header_data)
			bmp.write(bmp_content_data)


if __name__ == '__main__':
	i2c = I2C(0, scl=Pin(18), sda=Pin(19))
	slave_list = i2c.scan()

	if slave_list:
		oled = SSD1306_I2C(128, 64, i2c)

		run_test = ControllerGui(oled)
